package net.similarsu.device.sdk.dah;

import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;
import net.similarsu.device.sdk.dah.callback.FAnalyzerDataCallBack;
import net.similarsu.device.sdk.dah.callback.FMessCallBack;
import net.similarsu.device.sdk.dah.library.DahLibrary;
import net.similarsu.device.sdk.dah.struct.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.shell.Availability;
import org.springframework.shell.standard.ShellComponent;
import org.springframework.shell.standard.ShellMethod;
import org.springframework.shell.standard.ShellMethodAvailability;
import org.springframework.shell.standard.ShellOption;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import static net.similarsu.device.sdk.dah.library.DahLibrary.*;

@Profile("dah")
@ShellComponent
public class DahCommands {
    private static final Logger LOGGER = LoggerFactory.getLogger(DahCommands.class);

    private DahLibrary dahLibrary = Native.load("dhnetsdk", DahLibrary.class);

    private boolean init = false;
    private long login = 0L;
    private long alarmChan = 0L;

    private int nAlarmChan = 0;

    private FAnalyzerDataCallBack fAnalyzerDataCallBack = new FAnalyzerDataCallBack() {


        @Override
        public int invoke(NativeLong lAnalyzerHandle, int dwAlarmType, Pointer pAlarmInfo, Pointer pBuffer, int dwBufSize, NativeLong dwUser, int nSequence, Pointer reserved) {
            LOGGER.info("AT:[{}]", dwAlarmType);
            StringBuilder sAlarmType = new StringBuilder();
            switch (dwAlarmType) {
                case EVENT_IVS_ACCESS_CTL: {
                    DEV_EVENT_ACCESS_CTL_INFO devEventAccessCtlInfo = new DEV_EVENT_ACCESS_CTL_INFO();
                    GetPointerDataToStruct(pAlarmInfo, 0, devEventAccessCtlInfo);
                    sAlarmType.append("用户ID：");
                    sAlarmType.append(new String(devEventAccessCtlInfo.szUserID).trim());
                    sAlarmType.append("卡名：");
                    sAlarmType.append(new String(devEventAccessCtlInfo.szCardName).trim());
                    LOGGER.info("报警信息[{}]", sAlarmType);
                    //抓拍图片
                    if (dwBufSize > 0) {
                        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
                        String newName = sf.format(new Date());
                        FileOutputStream fout;
                        try {
                            String filename = "_byCardNo[" + new String(devEventAccessCtlInfo.szUserID).trim() +
                                    "_" + newName + "_IDInfoCapturePic.jpg";
                            fout = new FileOutputStream(filename);
                            fout.write(pBuffer.getByteArray(0, dwBufSize), 0, dwBufSize);
                            fout.close();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

                case EVENT_IVS_CITIZEN_PICTURE_COMPARE: {
                    DEV_EVENT_CITIZEN_PICTURE_COMPARE_INFO devEventCitizenPictureCompareInfo = new DEV_EVENT_CITIZEN_PICTURE_COMPARE_INFO();
                    GetPointerDataToStruct(pAlarmInfo, 0, devEventCitizenPictureCompareInfo);
                    sAlarmType.append("：门禁身份证刷卡信息")
                            .append(",身份证号码：" + new String(devEventCitizenPictureCompareInfo.szNumber).trim())
                            .append(",手机号码：" + new String(devEventCitizenPictureCompareInfo.szCellPhone).trim())
                            .append(",姓名：" + new String(devEventCitizenPictureCompareInfo.szCitizen).trim())
                            .append(",住址:" + new String(devEventCitizenPictureCompareInfo.szAddress).trim())
                            .append(",性别：" + devEventCitizenPictureCompareInfo.emSex)
                            .append(",出生日期:" + devEventCitizenPictureCompareInfo.stuBirth.dwYear + "-" + devEventCitizenPictureCompareInfo.stuBirth.dwMonth + "-" + devEventCitizenPictureCompareInfo.stuBirth.dwDay)
                            .append(",民族:" + devEventCitizenPictureCompareInfo.nEthnicity)
                            .append(",签发机关:" + new String(devEventCitizenPictureCompareInfo.szAuthority).trim())
                            .append(",有效期" + devEventCitizenPictureCompareInfo.stuValidityStart.dwYear + "-" + devEventCitizenPictureCompareInfo.stuValidityStart.dwMonth + "-" + devEventCitizenPictureCompareInfo.stuValidityStart.dwDay + "-"
                                    +devEventCitizenPictureCompareInfo.stuValidityEnd.dwYear + "-" + devEventCitizenPictureCompareInfo.stuValidityEnd.dwMonth + "-" + devEventCitizenPictureCompareInfo.stuValidityEnd.dwDay);

                    LOGGER.info("报警信息[{}]", sAlarmType);
                    //抓拍图片
                    if (dwBufSize > 0) {
                        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
                        String newName = sf.format(new Date());
                        FileOutputStream fout;
                        try {
                            String filename = "_byFace[" + new String(devEventCitizenPictureCompareInfo.szNumber).trim() +
                                    "_" + newName + ".jpg";
                            fout = new FileOutputStream(filename);
                            fout.write(pBuffer.getByteArray(devEventCitizenPictureCompareInfo.stuImageInfo[0].dwOffSet, devEventCitizenPictureCompareInfo.stuImageInfo[0].dwFileLenth), 0, devEventCitizenPictureCompareInfo.stuImageInfo[0].dwFileLenth);
                            fout.close();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        try {
                            String filename = "_byCard[" + new String(devEventCitizenPictureCompareInfo.szNumber).trim() +
                                    "_" + newName + ".jpg";
                            fout = new FileOutputStream(filename);
                            fout.write(pBuffer.getByteArray(devEventCitizenPictureCompareInfo.stuImageInfo[1].dwOffSet, devEventCitizenPictureCompareInfo.stuImageInfo[1].dwFileLenth), 0, devEventCitizenPictureCompareInfo.stuImageInfo[1].dwFileLenth);
                            fout.close();
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }

            return 0;
        }
    };

    private FMessCallBack fMessCallBack = new FMessCallBack() {
        @Override
        public int invoke(int lCommand, NativeLong lLoginID, Pointer pBuf, int dwBufLen, String pchDVRIP, int nDVRPort, NativeLong dwUser) {
            LOGGER.info("FB:[{}]", lCommand);
            StringBuilder sAlarmType = new StringBuilder();
            switch (lCommand){
                case DH_ALARM_ACCESS_CTL_EVENT:{
                    ALARM_ACCESS_CTL_EVENT_INFO alarmAccessCtlEventInfo = new ALARM_ACCESS_CTL_EVENT_INFO();
                    GetPointerDataToStruct(pBuf,0,alarmAccessCtlEventInfo);
                    sAlarmType.append(alarmAccessCtlEventInfo);
                    LOGGER.info("报警信息[{}]", sAlarmType);
                    break;
                }
            }
            return 0;
        }
    };

    @ShellMethod(key = "init", value = "init sdk")
    public void init(@ShellOption boolean log) {
        init = dahLibrary.CLIENT_Init(null, null) != 0;
        errorMsg("INIT");
        if (log) {
            LOG_SET_PRINT_INFO logSetPrintInfo = new LOG_SET_PRINT_INFO();
            logSetPrintInfo.dwSize = logSetPrintInfo.size();
            Pointer lpLogSetPrintInfo = logSetPrintInfo.getPointer();
            logSetPrintInfo.nPrintStrategy = 1;
            logSetPrintInfo.bSetPrintStrategy = 1;
            logSetPrintInfo.write();
            dahLibrary.CLIENT_LogOpen(lpLogSetPrintInfo);
            errorMsg("LOG");
        }
    }

    @ShellMethod(key = "cleanup", value = "clean up")
    public void cleanup() {
        dahLibrary.CLIENT_Cleanup();
        init = false;
        errorMsg("CLEANUP");
    }

    @ShellMethod(key = "login", value = "login")
    public void login(@ShellOption(defaultValue = "192.168.50.3") String ip, @ShellOption(defaultValue = "37777") int port, @ShellOption(defaultValue = "admin") String user
            , @ShellOption(defaultValue = "admin") String pass) {
        NET_DEVICEINFO_Ex netDeviceinfoEx = new NET_DEVICEINFO_Ex();
        Pointer netDeviceinfoExPointer = netDeviceinfoEx.getPointer();
        IntByReference intByReference = new IntByReference(0);
        login = dahLibrary.CLIENT_LoginEx2(ip, (short)port, user, pass, 0, null, netDeviceinfoExPointer, intByReference).longValue();
        netDeviceinfoEx.read();
        LOGGER.info("LOGIN:[{}]", login);
        errorMsg("LOGIN");
        dahLibrary.CLIENT_SetDVRMessCallBack(fMessCallBack,0);
        errorMsg("MESSCALLBACK");
    }

    @ShellMethod(key = "logout", value = "logout")
    public void logout() {
        dahLibrary.CLIENT_Logout(new NativeLong(login));
        login = -1;
        errorMsg("LOGOUT");
    }

    @ShellMethod(key = "setupalarmchan", value = "setup alarm channel")
    public void setupalarmchan() {
        alarmChan = dahLibrary.CLIENT_RealLoadPictureEx(new NativeLong(login), 0, EVENT_IVS_ALL, 1, fAnalyzerDataCallBack, null, null).longValue();
        errorMsg("RealLoadPictureEx");
    }

    @ShellMethod(key = "closealarmchan", value = "close alarm channel")
    public void closealarmchan() {
        dahLibrary.CLIENT_StopLoadPic(new NativeLong(alarmChan));
        alarmChan = 0L;
        errorMsg("CLOSE_ALARM_CHAN");
    }

    @ShellMethod(key = "nsetupalarmchan", value = "setup new alarm channel")
    public void nsetupalarmchan() {
        nAlarmChan = dahLibrary.CLIENT_StartListenEx(new NativeLong(login));
        errorMsg("StartListenEx");
    }

    @ShellMethod(key = "nclosealarmchan", value = "close new alarm channel")
    public void nclosealarmchan() {
        dahLibrary.CLIENT_StopListen(new NativeLong(login));
        alarmChan = 0L;
        errorMsg("StopListen");
    }

    @ShellMethodAvailability({"cleanup", "login"})
    public Availability checkInit() {
        return init ? Availability.available() : Availability.unavailable("exec init first!!!");
    }

    @ShellMethodAvailability({"logout", "setupalarmchan", "nsetupalarmchan"})
    public Availability checkLogin() {
        return login != -1 ? Availability.available() : Availability.unavailable("exec login first!!!");
    }

    @ShellMethodAvailability({"closealarmchan"})
    public Availability checkAlarmChan() {
        return alarmChan != 0 ? Availability.available() : Availability.unavailable("exec setupalarmchan first!!!");
    }


    private void errorMsg(String opt) {
        int errorCode = dahLibrary.CLIENT_GetLastError() & 0x80000000;
        LOGGER.error("OPT:[{}],CODE:[{}]", opt, errorCode);
    }

    private void GetPointerDataToStruct(Pointer pNativeData, long OffsetOfpNativeData, Structure pJavaStu) {
        pJavaStu.write();
        Pointer pJavaMem = pJavaStu.getPointer();
        pJavaMem.write(0, pNativeData.getByteArray(OffsetOfpNativeData, pJavaStu.size()), 0,
                pJavaStu.size());
        pJavaStu.read();
    }
}
